﻿using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;

namespace LaoLuo.Collections
{
    /// <summary>
    /// 线程安全的一键多值的容器
    /// </summary>
    /// <typeparam name="TKey">键的类型</typeparam>
    /// <typeparam name="TValue">值的类型</typeparam>
    /// <typeparam name="TValueWrapper">值的包裹的类型</typeparam>
    public class MultiValueDictionary<TKey, TValue, TValueWrapper> : IEnumerable<KeyValuePair<TKey, TValueWrapper>>
        where TValueWrapper : ICollection<TValue>, new()
    {
        /// <summary>
        /// 真实的容器
        /// </summary>
        private readonly ConcurrentDictionary<TKey, TValueWrapper> _innerDictionary;

        /// <summary>
        /// 初始化一个MultiValueDictionary&lt;TKey, TValue, TValueWrapper>
        /// </summary>
        /// <param name="keyComparer">键的相等比较器,可为空</param>
        public MultiValueDictionary(IEqualityComparer<TKey> keyComparer = null)
        {
            _innerDictionary = new ConcurrentDictionary<TKey, TValueWrapper>(keyComparer ?? EqualityComparer<TKey>.Default);
        }

        /// <summary>
        /// 获取键的集合
        /// </summary>
        public ICollection<TKey> Keys
        {
            get { return _innerDictionary.Keys; }
        }

        /// <summary>
        /// 获取值的集合
        /// </summary>
        public ICollection<TValueWrapper> Values
        {
            get { return _innerDictionary.Values; }
        }

        /// <summary>
        /// 设置或获取键对应的值
        /// </summary>
        /// <param name="key">键</param>
        /// <returns>键对应的值</returns>
        public TValueWrapper this[TKey key]
        {
            get { return _innerDictionary[key]; }

            set { _innerDictionary[key] = value; }
        }

        /// <summary>
        /// 添加一个指定键的值(如果指定的键尚不存在，则将键/值对,如果指定的键已存在,则在TValueWrapper中添加指定的值)
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        public void Add(TKey key, TValue value)
        {
            _innerDictionary.AddOrUpdate(key, new TValueWrapper {value}, (k, w) =>
                                                               {
                                                                   w.Add(value);
                                                                   return w;
                                                               });
        }

        /// <summary>
        /// 移除指定键
        /// </summary>
        /// <param name="key">键</param>
        /// <returns>是否成功移除了键</returns>
        public bool Remove(TKey key)
        {
            TValueWrapper w;
            return _innerDictionary.TryRemove(key, out w);
        }

        /// <summary>
        /// 确定容器是否包含键
        /// </summary>
        /// <param name="key">键</param>
        /// <returns>如果包含键返回true,否则返回false</returns>
        public bool ContainsKey(TKey key)
        {
            return _innerDictionary.ContainsKey(key);
        }

        /// <summary>
        /// remove all keys and values from this dictionary
        /// </summary>
        public void Clear()
        {
            _innerDictionary.Clear();
        }

        /// <summary>
        /// 获取键值对的枚举器
        /// </summary>
        /// <returns>枚举器</returns>
        public IEnumerator<KeyValuePair<TKey, TValueWrapper>> GetEnumerator()
        {
            return _innerDictionary.GetEnumerator();
        }

        /// <summary>
        /// 获取键值对的枚举器
        /// </summary>
        /// <returns>枚举器</returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }
}
